home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 1 Issue 2
/
PDCD-1 - Issue 02.iso
/
_utilities
/
utilities
/
004
/
dynamite
/
DynManText
< prev
next >
Wrap
Text File
|
1994-10-21
|
28KB
|
1,015 lines
_
/ \ ___ ___ _____ ╖ /_ __
/ ) / / / ) / ) / / ) / / /__)
/___/ (___/ / ( (___( / / ( (_ (_ (___
____/
Programmer's Guide
Straylight
16 Portland Street, Royal Leamington Spa,
Warwickshire, CV32á5HE
Telephone and facsimile: 01926á452639
_____________________________________________________________________________
⌐ 1994 Straylight
This documentation refers to Dynamite module version 1.10
The Dynamite software and accompanying documentation are to be
considered as `Freeware' -- they may be reproduced and distributed on
condition that they are not altered in any way and no profit is made
by so doing. You may supply the Dynamite module with any software
which uses it, including software for which a profit is made.
Because the program is licensed free of charge, there is no warranty
for the program, to the extent permitted by applicable law. Except
when otherwise stated in writing the copyright holders and/or other
parties provide the program `as is' without warranty of any kind,
either expressed or implied, including, but not limited to, the
implied warranties of merchantability and fitness for a particular
purpose. The entire risk as to the quality and performance of the
program is with you. Should the program prove defective, you assume
the cost of all necessary servicing, repair or correction.
The product described in this documentation is the subject of
continual development and, while all efforts are taken to ensure
that the information given is correct, Straylight cannot accept any
liability for loss or damage resulting from the use or misuse of this
product.
Trademarks
Acorn, Archimedes and RISC PC are trademarks of Acorn Computers Ltd.
ARM is a trademark of Advanced RISC Machines Ltd.
All other trademarks acknowledged.
_____________________________________________________________________________
Dynamite overview
What does Dynamite do?
One of the greatest problems facing module writers is that of
allocating memory. Although the Relocatable Module Area has been
provided to allow modules to allocate workspace, its design causes
it to fragment over a period of time.
Programmers have been aware of this problem for a long time, and
several have started to use the System Sprite Area as an alternative
source of memory, since it does not suffer from fragmentation in the
same way as the RMA.
Acorn have finally addressed this difficulty and enabled modules
running under RISCáOS 3.5 or later to create their own dynamic areas,
which they can then manage themselves, for example, by implementing a
shifting heap similar to that used by most applications.
Unfortunately this solution is not available to programs required to
run on machines earlier than the RISCáPC.
Dynamite is a small module which provides a solution to the problem
of memory allocation without causing fragmentation of the RMA,
abusing the Sprite area, or being specific to any particular
operating system versions. This means that code which uses Dynamite
should be able to run on any version of RISCáOS.
Running under RISCáOS 3.5 or later, Dynamite creates its own dynamic
area and implements within it a shifting heap which is compacted over
a period of time by a WIMP task.
Under earlier versions of RISCáOS, Dynamite shuffles the memory map
to create its own `dynamic area', and implements within it a
shifting heap as before.
The interface to the Dynamite memory manager is identical, whether or
not a real dynamic area is used. Since blocks are always allocated
within Dynamite's special area of memory, clients which require
blocks of memory and can cope with them being moved around can now
obtain them without fragmenting the RMA.
How Dynamite works
Operation under RISCáOS 3.5 or later
Dynamite's operation under RISCáOS 3.5 is fairly simple -- the new
facilities provided by OS_DynamicArea are used to create and resize
the heap as required.
Operation under RISCáOS versions prior to 3.5
Since early versions of RISCáOS do not provide calls for creating
dynamic areas, Dynamite takes matters into its own hands. It uses
the area of logical memory at the end of the System Sprite area (up
to &01800000) to build its heap.
Normally, the System Sprite Area is layed out as shown below:
[Picture: DynManDocs.Diag_1/1]
Only the shaded area used by the system sprites actually has physical
memory pages associated with it.
Dynamite creates its area at the other end of the System Sprite Area,
from 24M downwards, as shown overleaf.
[Picture: DynManDocs.Diag_1/2]
Operating system routines are intercepted to ensure that Dynamite's
maintenance of this area does not affect the normal operation of the
kernel's memory management.
It should be noted that because of this method of implementation,
there is a limit of 4M (assuming there are no System Sprites) on the
size of Dynamite's heap. The RMA also has a limit of 4M, and this
is rarely exceeded, so this is unlikely to cause a problem in
practice.
It should be noted that the Task Manager will show the size of the
Sprite area including Dynamite's area. However, OS_ReadDynamicArea
will return only the amount occupied by the System Sprites, allowing
programs which use sprites to store their data to work as before.
OS_ChangeDynamicArea will continue to work as before; only the area
containing the System Sprites will change in size.
Warning: To the best of our knowledge, there are no other programs
which use the area of memory at the end of the Sprite area. If
similar modules appear, there are likely to be severe compatibility
problems. It is for this reason that we have decided to publish the
interface to Dynamite.
_____________________________________________________________________________
Using Dynamite
Who can use Dynamite?
Straylight have decided to make this module `freeware'. It remains
at all times Copyright ⌐ 1994 Straylight, however it may be
distributed with products which wish to use it, whether or not they
are commercial. No charge may be made for Dynamite specifically,
and the module must not be altered in any way.
All products distributed with Dynamite must state in the main
documentation that Dynamite is ⌐ 1994 Straylight.
Loading Dynamite
Dynamite should normally be loaded from an Obey file in the following
way:
RMEnsure Dynamite 0.00 RMRun <My$Dir>.Dynamite
RMEnsure Dynamite 1.10 Error 0 Dynamite module is too old
It is important to note that the Dynamite module must be RMRun, not
just RMLoaded -- this will ensure that the Dynamite WIMP task is
started correctly.
_____________________________________________________________________________
About the Dynamite heap
Shifting heaps
Dynamite allocates blocks from a shifting heap. This means that
blocks allocated from the heap will be moved around in order to
close up any gaps created by freeing blocks. In a normal heap, for
example that implemented by OS_Heap or the C library's malloc
function, the free memory in the heap can become fragmented. For
example, consider a heap from which 3 blocks have been allocated:
[Picture: DynManDocs.Diag_3/1]
The lower area of the heap has been allocated, but there is a chunk
of free memory at the end, which can be claimed. If block 2 is now
freed, the heap would look like this:
[Picture: DynManDocs.Diag_3/2]
There are now two free areas which memory may be allocated, but since
they are not contiguous, the size of the largest block which can be
allocated is dictated by the size of the largest free area. If the
free space could be coalesced in some way, then obviously all the
free space in the heap is available for allocation.
Clearly, the only way to gather these free areas together is by
moving the allocated blocks. It is this property which defines the
shifting heap. The problem with a shifting heap is that the blocks
allocated in it can move whenever free space is generated within the
heap. Programs making use of such a memory manager must be able to
cope with this.
Dynamite's memory manager
Dynamite implements a shifting heap within its dynamic area. As a
result, programs making use of Dynamite must be able to deal with
their blocks of memory being moved. Since Dynamite may be used by
multiple clients, each must be aware that its blocks may be shifted
while it does not have control of the processor. For each block you
allocate, you must tell Dynamite the address of your pointer to the
block. This pointer is called the block's anchor pointer. This is
so that Dynamite can update your anchor when the block moves. Note
that you should not put anchors into application memory, since
Dynamite may have to update them while your application is paged out.
To make this easier, Dynamite allows you to allocate anchors from the
RMA very easily. You can then store the address of the anchor in
your own memory.
You should always address a Dynamite block through its anchor
pointer, rather than taking copies of the block address. If you
don't do this, Dynamite will correctly update the block's anchor
should the block move, leaving any other copies of the address
unchanged. Of course, you can assume that pointers remain valid
while you have control, but e.g. calling Wimp_Poll may cause them to
be invalidated, since Dynamite uses idle events to compact the heap.
Using Dynamite from interrupt routines
Most Dynamite routines are not re-entrant, so you should request a
callback before using them. You must also take into account that the
foreground application may have pointers to Dynamite blocks tem
porarily in registers or on the stack etc., which you should ensure
remain valid. To assist you in this, Dynamite will normally only
move blocks which you explicitly resize. However, if enough memory
is not available, Dynamite will attempt to compact the heap. You
must therefore disable this using the SWI Dynamite_Lock.
As long as the foreground task is guaranteed to not have access to
blocks used by your callback routine, or it has been written to cope
with this, then you will not have any problems.
Using Dynamite from SWIs
You should take careful note of the points raised in the previous
section when writing SWI handlers which use Dynamite, since your SWI
may well be called from a callback routine.
Using Dynamite from command line applications
You must be aware that the user may want to run your command line
application within a TaskWindow. This may cause your application to
lose control of the processor at arbitrary points within your
program, during which time, the rest of the desktop is active. This
means that other applications may cause blocks to move within the
Dynamite heap -- in particular, Dynamite may be compacting the heap
during this time. To prevent this from happening, you should lock
the heap while you are accessing Dynamite blocks and unlock it again
when you have finished, using the relevant SWIs.
The Dynamite relocation stack
To help you keep track of blocks when they move, you can save
pointers on a special stack. When you load the pointers back, they
will have been relocated so that they still point at the same data
object, even if it was within a Dynamite block which has been moved.
Block IDs
When you allocate a block using Dynamite_Alloc, you can specify a
block ID to associate with it. This can be any 32-bit value you
like, although it should be something unlikely to conflict with
other client's IDs, e.g.:
* A module's base address
* An application's task handle or start time
If you want your program to have multiple IDs, you could divide the
ID value into a `magic' field (say 24 bits of module base address)
and an index number.
Later, you can free all blocks with a particular ID. This is useful
when you want to free all the blocks associated with a particular
object when that object is destroyed. For example, during
development of a module, you could free all its Dynamite blocks in
the finalisation code.
Compaction of the Dynamite heap
The Dynamite module has a WIMP task which will partially tidy the
heap while the processor is idle. This means that the process of
removing free space from the heap is distributed over a period of
time, and will probably not be noticeable in average use.
If you are writing a program which will not multitask, you should
perform this tidying yourself from time to time, using the
appropriate Dynamite SWIs.
_____________________________________________________________________________
SWI calls
Standard features
Dynamite SWIs obey the following conventions:
* Arguments are passed in registers, starting from R0. Return values
are also given in registers.
* All registers not explicitly used to return results are preserved.
* On exit, the V flag is used to indicate an error status. The carry
flag may be used to return information as well, although this is
documented with the appropriate SWIs when it happens. In all other
cases, the C, N and Z flags are preserved when there is no error.
Dynamite_Alloc (SWI &4A3C0)
Allocates a block of memory from the Dynamite heap
On entry
R0 = address of block anchor
R1 = size of block to allocate, in bytes
R2 = block ID, or 0 for none
On exit
R0, R1 preserved
R2 = address of allocated block
Interrupts
Interrupt status is undefined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI allocates a block from the Dynamite heap.
This SWI may cause blocks to move within the Dynamite heap.
Related SWIs
* Dynamite_Free
Dynamite_Free (SWI &4A3C1)
Frees a Dynamite block, releasing the memory it used
On entry
R0 = pointer to anchor of block to be freed
On exit
--
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will free a block in the Dynamite heap, releasing the memory
it used for later reallocation. The free memory will later be
returned to the operating system during compaction.
Related SWIs
* Dynamite_Alloc
* Dynamite_FreeWithID
Dynamite_FreeWithID (SWI &4A3C2)
Frees all blocks with a given block ID
On entry
R0 = block ID (must be non-zero)
On exit
--
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will free all blocks which have a specified block ID.
Related SWIs
* Dynamite_Free
Dynamite_BlockInfo (SWI &4A3C3)
Returns information about a Dynamite block
On entry
R0 = address of block anchor
On exit
R0 preserved
R1 = address of block
R2 = current size of block, in bytes
R3 = block ID, as passed to Dynamite_Alloc
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is re-entrant
Use
This SWI returns various pieces of information about a Dynamite
block.
The size in R2 is the byte aligned size given to Dynamite_Alloc when
the block was created, possibly altered subsequently by
Dynamite_Resize or Dynamite_MidExtend.
Related SWIs
None
Dynamite_ChangeID (SWI &4A3C4)
Changes the ID of a given block, or all blocks with a given ID
On entry
R0 = address of anchor for block, or 0 for all blocks
R1 = new ID
R2 = old ID (if R0 = 0)
On exit
Ö
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will change the ID of the block whose anchor is passed in
R0, or the ID of all the blocks which have the ID passed in R2,
if R0 = 0.
Related SWIs
None
Dynamite_Resize (SWI &4A3C5)
Alters the size of a Dynamite block
On entry
R0 = address of block anchor
R1 = new size of block, in bytes
On exit
R0 preserved
R1 = address of block, which may have moved
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will change a block's size. The exact behaviour of this
routine depends on whether the new size is greater than or less than
the old size. If you are reducing the size of a block, bytes will be
removed from the end. Out-of-memory errors will not be returned.
If you are extending a block, bytes are added at the end. An out-of-
memory error may be returned if there is not enough memory to extend
the block.
This SWI may cause blocks to move within the Dynamite heap.
Related SWIs
* Dynamite_MidExtend
Dynamite_MidExtend (SWI &4A3C6)
Inserts or deletes bytes at a given offset within a block
On entry
R0 = address of block anchor
R1 = offset within block to add or remove bytes
R2 = signed number of bytes to add
On exit
R0 preserved
R1 = address of block, which may have moved
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This call will, depending on whether R2 is positive or negative,
insert or remove bytes from a Dynamite block starting at the offset
given in R1. This may of course cause the block's size to change.
Always after a call to Dynamite_MidExtend, the data that was
previously at offset R1 is moved to offset R1+R2.
The diagrams below show the effects of inserting or removing bytes
from a block:
[Picture: DynManDocs.Diag_4/1]
Diagram 1: Inserting bytes
[Picture: DynManDocs.Diag_4/2]
Diagram 2: Removing bytes
This SWI may cause blocks to move within the Dynamite heap.
Related SWIs
* Dynamite_Resize
Dynamite_Save (SWI &4A3C7)
Saves some registers on Dynamite's relocation stack
On entry
R0 = bit mask of registers to save
Other registers as described below
On exit
--
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will save the registers specified in R0 on Dynamite's
relocation stack. R0 should contain a bit set for each register
that you want saved -- i.e. bit 1 set to save R1, etc.
You cannot usefully save R9-R15 or R0, so the corresponding bits of
R0 should not be set on entry.
The stack is ascending, and follows the normal ARM rules for
ascending stacks. Hence if you save R1-R7 on the stack, the saved
R7 will be the first register to be removed.
The upper two bytes of R0 are ignored by this SWI. Therefore R0 on
entry can actually contain an STM instruction specifying the required
registers.
Related SWIs
* Dynamite_Load
Dynamite_Load (SWI &4A3C8)
Restores registers from Dynamite's relocation stack
On entry
R0 = bit mask of registers to load
On exit
As described below
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will load the registers specified in R0 from Dynamite's
relocation stack. R0 should contain a bit set for each register that
you want loaded -- i.e. bit 1 set to load R1, etc.
You must not load R9-R15, so the corresponding bits of R0 should not
be set on entry.
The stack is ascending, and follows the normal ARM rules for
ascending stacks. Hence if you save R1-R7 on the stack, the saved
R7 will be the first register to be removed.
The upper two bytes of R0 are ignored by this SWI. Therefore R0 on
entry can actually contain an LDM instruction specifying the required
registers.
Related SWIs
* Dynamite_Save
Dynamite_Reduce (SWI &4A3C9)
Performs a partial compaction of the Dynamite heap
On entry
--
On exit
C set if no compaction performed, clear otherwise
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This call will partially compact Dynamite's heap. It may fail
(returning C set) if either the heap is already compact, or if the
heap is locked. Calling Dynamite_Reduce in a loop until it returns
with C set will result in the heap being fully compacted.
This SWI may cause blocks to move within the Dynamite heap.
Related SWIs
* Dynamite_Compact
Dynamite_Compact (SWI &4A3CA)
Fully compacts the Dynamite heap
On entry
--
On exit
C set if no action performed, clear otherwise
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This routine will fully compact Dynamite's heap, returning any free
space to the operating system. It may fail (returning C set) either
if the heap is already compact, or if the heap is locked.
This SWI may cause blocks to move within the Dynamite heap.
Related SWIs
* Dynamite_Reduce
Dynamite_Lock (SWI &4A3CB)
Locks the heap, preventing blocks from moving
On entry
--
On exit
--
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This call will lock the Dynamite heap, so that blocks will not
normally be moved around (e.g. during compaction). Blocks may still
be moved when they are resized, however. The heap may be unlocked
again by calling Dynamite_Unlock. Calls to Dynamite_Lock may be
nested.
When locked, the heap behaves much like a normal nonshifting heap,
and can become fragmented.
Related SWIs
* Dynamite_Unlock
Dynamite_Unlock (SWI &4A3CC)
Unlocks the Dynamite heap
On entry
--
On exit
--
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This call will cancel the effects of a previous Dynamite_Lock.
Related SWIs
* Dynamite_Lock
Dynamite_ClaimAnchor (SWI &4A3CD)
Allocates an anchor from the RMA
On entry
--
On exit
R0 = address of anchor
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
Allocates an anchor from the RMA. This should be used by
applications to obtain anchors, so that Dynamite does not try to
access application memory which has been paged out when it moves
blocks.
Related SWIs
* Dynamite_ReleaseAnchor
Dynamite_ReleaseAnchor (SWI &4A3CE)
Releases an anchor allocated by Dynamite_ClaimAnchor
On entry
R0 = address of anchor
On exit
--
Interrupts
Interrupt status is not defined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is not re-entrant
Use
This SWI will allow you to release an anchor you claimed with
Dynamite_ClaimAnchor, so it can be used again.
Related SWIs
* Dynamite_ClaimAnchor
Dynamite_ReadSpriteSize (SWI &4A3CF)
Reads the total size of the System Sprite Area
On entry
--
On exit
R0 = size of the System Sprite Area in bytes
Interrupts
Interrupt status is undefined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is re-entrant
Use
This SWI returns the size of the System Sprite Area in bytes,
including the Dynamite area if present. It is anticipated that
programs requiring to enumerate the allocation of all memory in the
system will use code similar to the following to read the Sprite
Area size:
; --- Read sprite area size ---
SWI XDynamite_ReadSpriteSize
MOVVC R1,R0
MOVVS R0,#3
SWIVS XOS_ReadDynamicArea
Related SWIs
None.
Dynamite_Describe (SWI &4A3D0)
Describes the Dynamite area at the time of the call
On entry
Ö
On exit
R0 = handle of dynamic area, or -1 for pre-RISC OS 3.5 machines
R1 = total size of Dynamite area
R2 = size of unused area
Interrupts
Interrupt status is undefined
Fast interrupts are enabled
Processor mode
Processor is in SVC mode
Re-entrancy
SWI is re-entrant
Use
This call returns some information on the Dynamite area. The sizes
returned are only valid for the time that the caller has control and
doesn't call another Dynamite SWI.
Related SWIs
None.